import crypto from "crypto";
import fs from "fs";
import { promisify } from "util";

const readFile = promisify(fs.readFile);
/**
 * 计算文件内容的MD5哈希
 * @param {Buffer} buffer - 文件内容缓冲区
 * @returns {string} MD5哈希字符串
 */
/**
 * 计算文件哈希（支持Buffer或文件路径）
 */
export async function calculateFileHash(source) {
  try {
    let buffer;

    // 处理Buffer类型
    if (Buffer.isBuffer(source)) {
      buffer = source;
    }
    // 处理文件路径字符串
    else if (typeof source === "string") {
      buffer = await readFile(source);
    }
    // 处理Multer文件对象
    else if (source && source.path) {
      buffer = await readFile(source.path);
    }
    // 处理Multer文件对象（内存存储）
    else if (source && source.buffer) {
      buffer = source.buffer;
    } else {
      throw new BadRequestError("不支持的文件源类型");
    }

    if (!buffer || buffer.length === 0) {
      throw new BadRequestError("文件内容为空");
    }

    return crypto.createHash("md5").update(buffer).digest("hex");
  } catch (error) {
    if (error.code === "ENOENT") {
      throw new BadRequestError("文件不存在");
    }
    throw error;
  }
}
/**
 * 计算大文件的哈希（采样计算）
 */
export async function calculateLargeFileHash(source, sampleSize = 2 * 1024 * 1024) {
  const buffer = await getFileBuffer(source);
  const length = buffer.length;
  
  // 如果文件小于采样大小的3倍，直接计算全量哈希
  if (length <= sampleSize * 3) {
    return calculateFileHash(buffer);
  }

  const hash = crypto.createHash('md5');
  
  // 采样文件头、中、尾部分
  hash.update(buffer.subarray(0, Math.min(sampleSize, length)));
  
  const midStart = Math.floor(length / 2) - sampleSize / 2;
  hash.update(buffer.subarray(midStart, midStart + sampleSize));
  
  hash.update(buffer.subarray(Math.max(0, length - sampleSize), length));
  
  return hash.digest('hex');
}

async function getFileBuffer(source) {
  if (Buffer.isBuffer(source)) return source;
  if (typeof source === 'string') return await readFile(source);
  if (source?.path) return await readFile(source.path);
  if (source?.buffer) return source.buffer;
  
  throw new BadRequestError('不支持的文件源类型');
}